package com.lonely.product.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.lonely.common.core.domain.BaseEntity;
import com.lonely.common.core.domain.StatusInfo;
import com.lonely.common.core.page.Condition;
import com.lonely.common.enums.CommonStatus;
import com.lonely.common.enums.DataScope;
import com.lonely.common.threadlocals.DataPermissionThreadLocal;
import com.lonely.common.utils.SecurityUtils;
import com.lonely.common.utils.enums.ExtractStatusInfoUtil;
import com.lonely.order.domain.dto.api.NumberInfo;
import com.lonely.order.domain.dto.order.AddOrderLogDTO;
import com.lonely.order.domain.entity.SysOrder;
import com.lonely.order.domain.entity.SysOrderPart;
import com.lonely.order.domain.vo.order.OrderQuantityInfo;
import com.lonely.order.service.IOrderLogService;
import com.lonely.order.service.IOrderPartService;
import com.lonely.order.service.IOrderService;
import com.lonely.product.domain.dto.cuttingbed.AlreadyLabelRackDTO;
import com.lonely.product.domain.dto.cuttingbed.QueryCuttingBedPageDTO;
import com.lonely.product.domain.dto.cuttingbed.StartCuttingDTO;
import com.lonely.product.domain.dto.cuttingbed.TypeInCuttingQuantitySubmitDTO;
import com.lonely.product.domain.entity.SysCuttingBed;
import com.lonely.product.domain.entity.SysCuttingBedSize;
import com.lonely.product.domain.vo.cuttingbed.QueryCuttingBedPageVO;
import com.lonely.product.domain.vo.cuttingbed.TypeInCuttingQuantityDetailVO;
import com.lonely.product.enums.CuttingBedEnum;
import com.lonely.product.mapper.SysCuttingBedMapper;
import com.lonely.product.service.ICuttingBedService;
import com.lonely.product.service.ICuttingBedSizeService;
import com.lonely.product.service.IOrderSewingService;
import com.lonely.purchase.domain.entity.SysMaterialPurchase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : 黄志标
 * @date: 2025/7/24 14:01
 * @description: 裁床服务实现类
 */
@Service
public class CuttingBedServiceImpl extends ServiceImpl<SysCuttingBedMapper, SysCuttingBed> implements ICuttingBedService {

    @Autowired
    private IOrderService orderService;

    @Autowired
    private ICuttingBedSizeService cuttingBedSizeService;

    @Autowired
    private IOrderPartService orderPartService;

    @Autowired
    private IOrderSewingService orderSewingService;

    @Autowired
    private IOrderLogService orderLogService;

    /**
     * 裁床分页查询
     *
     * @param queryDto
     * @return
     */
    @Override
    public Page<QueryCuttingBedPageVO> page(QueryCuttingBedPageDTO queryDto) {
        DataPermissionThreadLocal.setDataPermission(DataScope.ORDER_FACTORY, "o.factory_permission");
        Page<QueryCuttingBedPageVO> page = Condition.page(queryDto);
        return super.getBaseMapper().page(page, queryDto);
    }

    /**
     * 已排唛架
     *
     * @param alreadyLabelRackDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void alreadyLabelRack(AlreadyLabelRackDTO alreadyLabelRackDTO) {
        List<SysCuttingBed> sysCuttingBeds = super.listByIds(alreadyLabelRackDTO.getCuttingBedIds());
        if (CollUtil.isEmpty(sysCuttingBeds)) {
            return;
        }

        boolean match = sysCuttingBeds.stream().allMatch(sysCuttingBed -> Objects.equals(sysCuttingBed.getStatus(), CuttingBedEnum.CuttingBedStatusEnum.TO_BE_LABEL_RACK.getStatus()));
        Assert.isTrue(match, "存在非待排唛架状态的数据");

        sysCuttingBeds = sysCuttingBeds.stream().peek(sysCuttingBed -> {
            sysCuttingBed.setStatus(CuttingBedEnum.CuttingBedStatusEnum.TO_BE_CUTTING.getStatus());
            sysCuttingBed.setUpdateBy(SecurityUtils.getUserId());
            sysCuttingBed.setOperator(SecurityUtils.getUserId());
        }).collect(Collectors.toList());
        super.updateBatchById(sysCuttingBeds);

        // 添加操作日志
        List<Long> produceOrderIds = sysCuttingBeds.stream().map(SysCuttingBed::getProduceOrderId).distinct().collect(Collectors.toList());
        List<Long> orderIds = this.orderService.getOrderIdsByProduceOrderIds(produceOrderIds);
        List<AddOrderLogDTO> addOrderLogs = orderIds.stream().map(x -> {
            AddOrderLogDTO addOrderLogDTO = new AddOrderLogDTO();
            addOrderLogDTO.setOrderId(x);
            addOrderLogDTO.setTitle("已排唛架");
            return addOrderLogDTO;
        }).collect(Collectors.toList());
        this.orderLogService.batchAddOrderLog(addOrderLogs);
    }

    /**
     * 开始裁床
     *
     * @param startCuttingDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startCutting(StartCuttingDTO startCuttingDTO) {
        List<SysCuttingBed> sysCuttingBeds = super.listByIds(startCuttingDTO.getCuttingBedIds());
        if (CollUtil.isEmpty(sysCuttingBeds)) {
            return;
        }

        boolean match = sysCuttingBeds.stream().allMatch(sysCuttingBed -> Objects.equals(sysCuttingBed.getStatus(), CuttingBedEnum.CuttingBedStatusEnum.TO_BE_CUTTING.getStatus()));
        Assert.isTrue(match, "存在非待裁剪状态的数据");

        sysCuttingBeds = sysCuttingBeds.stream().peek(sysCuttingBed -> {
            sysCuttingBed.setStatus(CuttingBedEnum.CuttingBedStatusEnum.DOING_CUTTING.getStatus());
            sysCuttingBed.setUpdateBy(SecurityUtils.getUserId());
            sysCuttingBed.setCuttingBedStartTime(new Date());
            sysCuttingBed.setOperator(SecurityUtils.getUserId());
        }).collect(Collectors.toList());
        super.updateBatchById(sysCuttingBeds);

        // 添加操作日志
        List<Long> produceOrderIds = sysCuttingBeds.stream().map(SysCuttingBed::getProduceOrderId).distinct().collect(Collectors.toList());
        List<Long> orderIds = this.orderService.getOrderIdsByProduceOrderIds(produceOrderIds);
        List<AddOrderLogDTO> addOrderLogs = orderIds.stream().map(x -> {
            AddOrderLogDTO addOrderLogDTO = new AddOrderLogDTO();
            addOrderLogDTO.setOrderId(x);
            addOrderLogDTO.setTitle("开始裁床");
            return addOrderLogDTO;
        }).collect(Collectors.toList());
        this.orderLogService.batchAddOrderLog(addOrderLogs);
    }

    /**
     * 查询录入裁床数详情数据
     *
     * @param cuttingId
     * @return
     */
    @Override
    public TypeInCuttingQuantityDetailVO typeInCuttingQuantityDetail(Long cuttingId) {
        SysCuttingBed sysCuttingBed = getCuttingById(cuttingId);

        TypeInCuttingQuantityDetailVO typeInCuttingQuantityDetailVO = new TypeInCuttingQuantityDetailVO();
        typeInCuttingQuantityDetailVO.setId(sysCuttingBed.getId());
        typeInCuttingQuantityDetailVO.setProduceOrderId(sysCuttingBed.getProduceOrderId());
        typeInCuttingQuantityDetailVO.setSizes(this.getCuttingQuantityTableInfo(sysCuttingBed));
        typeInCuttingQuantityDetailVO.setCuttingBedEmployee(sysCuttingBed.getCuttingBedEmployee());
        typeInCuttingQuantityDetailVO.setWage(sysCuttingBed.getWage());
        typeInCuttingQuantityDetailVO.setRemark(sysCuttingBed.getRemark());
        return typeInCuttingQuantityDetailVO;
    }

    /**
     * 录入裁床数
     *
     * @param submitDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void typeInCuttingQuantity(TypeInCuttingQuantitySubmitDTO submitDto) {
        SysCuttingBed cuttingById = this.getCuttingById(submitDto.getId());
        Assert.isTrue(CollUtil.size(submitDto.getSizes().getData()) >= 1, "没有裁床数据信息");

        // 计算金额
        int allQuantity = 0;
        for (int i = 1; i < submitDto.getSizes().getData().size(); i++) {
            Map<String, Object> cuttingSizeData = submitDto.getSizes().getData().get(i);

            // 获取当前部件的尺码数量
            int currentTotal = cuttingSizeData.keySet().stream().filter(x -> !Objects.equals(x, "type") && !Objects.equals(x, "total"))
                    .filter(x -> {
                        String quantity = Convert.toStr(cuttingSizeData.get(x));
                        return StrUtil.isNotBlank(quantity);
                    })
                    .mapToInt(x -> Convert.toInt(cuttingSizeData.get(x)))
                    .sum();
            allQuantity += currentTotal;
        }
        String amount = NumberUtil.mul(Convert.toStr(allQuantity), submitDto.getWage()).stripTrailingZeros().toPlainString();

        cuttingById.setWage(submitDto.getWage());
        cuttingById.setAmount(amount);
        cuttingById.setCuttingBedEmployee(submitDto.getCuttingBedEmployee());
        cuttingById.setCuttingBedQuantity(allQuantity);
        cuttingById.setCuttingBedEndTime(new Date());
        cuttingById.setStatus(CuttingBedEnum.CuttingBedStatusEnum.COMPLETED.getStatus());
        cuttingById.setRemark(submitDto.getRemark());
        cuttingById.setUpdateBy(SecurityUtils.getUserId());
        super.updateById(cuttingById);

        // 更新裁床件明细
        this.cuttingBedSizeService.updateSize(cuttingById.getId(), submitDto.getSizes());

        // 添加操作日志
        List<Long> orderIds = this.orderService.getOrderIdsByProduceOrderIds(Lists.newArrayList(cuttingById.getProduceOrderId()));
        List<AddOrderLogDTO> addOrderLogs = orderIds.stream().map(x -> {
            AddOrderLogDTO addOrderLogDTO = new AddOrderLogDTO();
            addOrderLogDTO.setOrderId(x);
            addOrderLogDTO.setTitle("录入裁床数");
            return addOrderLogDTO;
        }).collect(Collectors.toList());
        this.orderLogService.batchAddOrderLog(addOrderLogs);

        // 修改订单状态为车缝中
        this.orderService.updateOrderStatusToInTheCarSeam(cuttingById.getProduceOrderId());
//        this.orderService.update(new LambdaUpdateWrapper<SysOrder>()
//                .eq(SysOrder::getProduceOrderId, cuttingById.getProduceOrderId())
//                .eq(SysOrder::getStatusInt, OrderEnum.OrderStatus.CUTTING_IN_PROGRESS.getStatus())
//                .set(SysOrder::getStatusInt, OrderEnum.OrderStatus.IN_THE_CAR_SEAM.getStatus())
//                .set(SysOrder::getStatus, OrderEnum.OrderStatus.IN_THE_CAR_SEAM.getDesc())
//        );

        // 生成车缝数据
        this.orderSewingService.createOrderSewing(cuttingById.getProduceOrderId());
    }

    /**
     * 判断该订单是否已存在裁床数据
     *
     * @param produceOrderId
     * @return
     */
    @Override
    public boolean alreadyExistsCuttingBed(Long produceOrderId) {
        int count = super.count(new LambdaQueryWrapper<SysCuttingBed>()
                .eq(SysCuttingBed::getProduceOrderId, produceOrderId)
        );
        return count > 0;
    }

    /**
     * 生成待排唛架状态的裁床单
     *
     * @param materialPurchase
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createToBeLabelRackCuttingBed(SysMaterialPurchase materialPurchase) {
        SysCuttingBed sysCuttingBed = new SysCuttingBed();
        sysCuttingBed.setProduceOrderId(materialPurchase.getProduceOrderId());
        sysCuttingBed.setFactoryId(materialPurchase.getFactoryId());
        sysCuttingBed.setCuttingBedStartTime(null);
        sysCuttingBed.setCuttingBedEndTime(null);
        sysCuttingBed.setCuttingBedEmployee(null);
        sysCuttingBed.setCuttingBedQuantity(0);
        sysCuttingBed.setWage(null);
        sysCuttingBed.setAmount(null);
        sysCuttingBed.setTailQuantity(0);
        sysCuttingBed.setOperator(null);
        sysCuttingBed.setStatus(CuttingBedEnum.CuttingBedStatusEnum.TO_BE_LABEL_RACK.getStatus());
        sysCuttingBed.setCreateBy(SecurityUtils.getUserId());
        sysCuttingBed.setUpdateBy(SecurityUtils.getUserId());
        super.save(sysCuttingBed);
    }

    /**
     * 获取裁床管理状态信息
     *
     * @param queryDto
     * @return
     */
    @Override
    public List<StatusInfo> getStatusInfo(QueryCuttingBedPageDTO queryDto) {
        // 去除状态过滤
        queryDto.setCuttingBedStatus(null);
        // 添加数据权限过滤
        DataPermissionThreadLocal.setDataPermission(DataScope.ORDER_FACTORY, "o.factory_permission");
        List<StatusInfo> statusTotals = super.getBaseMapper().getStatusTotals(queryDto);
        return ExtractStatusInfoUtil.extractStatusInfos(statusTotals, CuttingBedEnum.CuttingBedStatusEnum.values());
    }

    /**
     * 获取指定订单号对应的裁床数
     *
     * @param produceOrderId
     * @return
     */
    @Override
    public Integer getCuttingBedQuantity(Long produceOrderId) {
        SysCuttingBed cuttingBed = super.getOne(new LambdaQueryWrapper<SysCuttingBed>()
                .eq(SysCuttingBed::getProduceOrderId, produceOrderId)
                .eq(SysCuttingBed::getStatus, CuttingBedEnum.CuttingBedStatusEnum.COMPLETED.getStatus())
        );
        Assert.notNull(cuttingBed, "未查询到该订单的裁床信息");
        return cuttingBed.getCuttingBedQuantity();
    }

    /**
     * 获取裁床数量表格信息
     *
     * @param sysCuttingBed
     * @return
     */
    private OrderQuantityInfo getCuttingQuantityTableInfo(SysCuttingBed sysCuttingBed) {
        SysOrder sysOrder = this.orderService.getOne(new LambdaQueryWrapper<SysOrder>().eq(SysOrder::getProduceOrderId, sysCuttingBed.getProduceOrderId()));
        Assert.notNull(sysOrder, "订单不存在");

        List<OrderQuantityInfo.Column> columns = new ArrayList<>();
        List<Map<String, Object>> datas = new ArrayList<>();

        // 添加默认列
        columns.add(new OrderQuantityInfo.Column().setTitle("尺码").setKey("type"));

        if (StrUtil.isNotEmpty(sysOrder.getOrderInfo())) {
            List<NumberInfo> orderInfoNumbers = JSON.parseArray(sysOrder.getOrderInfo(), NumberInfo.class);
            if (CollUtil.isNotEmpty(orderInfoNumbers)) {
                // 提取所有的尺码
                List<String> sizeNames = orderInfoNumbers.stream().map(NumberInfo::getSizeName).collect(Collectors.toList());
                sizeNames.forEach(sizeName -> {
                    columns.add(new OrderQuantityInfo.Column().setKey(sizeName).setTitle(sizeName));
                });

                // 处理订单数
                Map<String, Object> sizeData = new LinkedHashMap<>();
                sizeData.put("type", "订单数");

                orderInfoNumbers.forEach(numberInfo -> {
                    sizeData.put(numberInfo.getSizeName(), numberInfo.getQuantity());
                });

                // 添加合计列
                columns.add(new OrderQuantityInfo.Column().setTitle("合计").setKey("total"));
                sizeData.put("total", sysOrder.getQuantity());

                datas.add(sizeData);

                // 处理裁床件数
                List<SysCuttingBedSize> cuttingBedSizes = this.cuttingBedSizeService.list(new LambdaQueryWrapper<SysCuttingBedSize>()
                        .eq(SysCuttingBedSize::getCuttingBedId, sysCuttingBed.getId())
                        .eq(SysCuttingBedSize::getStatus, CommonStatus.ENABLE.code)
                );

                // 根据部件进行区分
                boolean isSuit = this.orderService.isSuit(sysCuttingBed.getProduceOrderId());
                if (isSuit) {
                    // 套装
                    Map<Long, String> orderPartMap = this.orderPartService.list(new LambdaQueryWrapper<SysOrderPart>()
                            .eq(SysOrderPart::getProduceOrderId, sysCuttingBed.getProduceOrderId())
                    ).stream().collect(Collectors.toMap(BaseEntity::getId, SysOrderPart::getPartLibrary));

                    orderPartMap.forEach((orderPartId, partLibrary) -> {
                        Map<String, Integer> cuttingBedSizeMap = cuttingBedSizes.stream()
                                .filter(x -> Objects.equals(x.getOrderPartId(), orderPartId))
                                .collect(Collectors.toMap(SysCuttingBedSize::getSizeName, SysCuttingBedSize::getQuantity, (x, y) -> y));
                        Map<String, Object> cuttingSizeData = new LinkedHashMap<>();
                        cuttingSizeData.put("type", String.format("%s-裁床数", partLibrary));
                        for (String sizeName : sizeNames) {
                            cuttingSizeData.put(sizeName, cuttingBedSizeMap.getOrDefault(sizeName, null));
                        }
                        // 添加合计列
                        int cuttingTotal = cuttingBedSizes.stream()
                                .filter(x -> Objects.equals(x.getOrderPartId(), orderPartId))
                                .mapToInt(x -> ObjectUtil.defaultIfNull(x.getQuantity(), 0)).sum();
                        cuttingSizeData.put("total", cuttingTotal);
                        datas.add(cuttingSizeData);
                    });

                } else {
                    // 非套装
                    Map<String, Integer> cuttingBedSizeMap = cuttingBedSizes.stream().collect(Collectors.toMap(SysCuttingBedSize::getSizeName, SysCuttingBedSize::getQuantity, (x, y) -> y));
                    Map<String, Object> cuttingSizeData = new LinkedHashMap<>();
                    cuttingSizeData.put("type", "裁床数");
                    for (String sizeName : sizeNames) {
                        cuttingSizeData.put(sizeName, cuttingBedSizeMap.getOrDefault(sizeName, null));
                    }
                    // 添加合计列
                    int cuttingTotal = cuttingBedSizes.stream().mapToInt(x -> ObjectUtil.defaultIfNull(x.getQuantity(), 0)).sum();
                    cuttingSizeData.put("total", cuttingTotal);
                    datas.add(cuttingSizeData);
                }

            }
        }
        return new OrderQuantityInfo().setColumns(columns).setData(datas);
    }


    /**
     * 根据id获取对应裁床信息
     *
     * @param cuttingId
     * @return
     */
    private SysCuttingBed getCuttingById(Long cuttingId) {
        SysCuttingBed sysCuttingBed = super.getById(cuttingId);
        Assert.notNull(sysCuttingBed, "该裁床不存在");
        return sysCuttingBed;
    }
}
